<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>考试</title>
    <link rel="icon" type="image/png" href="../img/icon.png">
    <link rel="stylesheet" href="../css/toastr.min.css">
    <link rel="stylesheet" href="../css/all.css">
    <style>
        body {
            background-color: #ccc;
        }
        #app {
            display: flex;
            min-height: 600px;
            color: #333;
            padding: 10px;

            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            overflow: hidden;
        }
        .menu-left {
            background-color: white;
            width: 300px;
            min-width: 300px;
            overflow-y: auto;
        }
        .menu-left .title {
            display: inline-block;
            color: white;
            background-color: #5d9cec;
            border-radius: 10px;
            padding: 2px 10px;
            font-size: 20px;
            cursor: pointer;
            margin-left: 5px;
            margin-bottom: 10px;
        }
        .stu-name {
            font-size: 24px;
            font-weight: bold;
            border-bottom: 1px solid #333;
            padding: 10px 5px;
            margin-bottom: 10px;
            display: flex;
            justify-content: space-between;
        }
        .q-list {
            border: 1px solid #ccc;
            padding: 5px;
            display: flex;
            flex-wrap: wrap;
            margin-bottom: 10px;
            border-left: none;
        }
        .q-list .q-item {
            width: 44px;
            height: 44px;
            background-color: #5d9cec;
            box-shadow: 2px 2px 5px 2px #5d9cec;
            margin: 5px;
            text-align: center;
            line-height: 44px;
            font-size: 24px;
            font-weight: bold;
            cursor: pointer;
        }
        .q-list .q-complete {
            background-color: #388e3c;
            box-shadow: 2px 2px 5px 2px #388e3c;
            color: #fff;
        }
        .q-list .q-show {
            background-color: #00e7ff;
            box-shadow: 2px 2px 5px 2px #00e7ff;
            color: #fff;
        }

        .menu-right {
            background-color: white;
            flex: 1;
            padding: 20px;
            overflow: auto;
        }

        .description {
            font-size: 18px;
            margin-bottom: 10px;
        }
        .description .q-title {
            display: inline-block;
            color: white;
            background-color: #5d9cec;
            border-radius: 5px;
            padding: 2px 10px;
            font-size: 18px;
        }
        .description .q-txt {
            margin: 5px 0;
            border: 1px solid #ccc;
            padding: 10px;
            line-height: 20px;
            white-space: pre-wrap;
            font-weight: bold;
            letter-spacing: 1px;
        }
        .answer {
            font-size: 18px;
        }
        .answer .a-title {
            display: inline-block;
            color: white;
            background-color: #5d9cec;
            border-radius: 5px;
            padding: 2px 10px;
            font-size: 18px;
        }
        .answer .a-txt {
            width: 100%;
            box-sizing: border-box;
            margin: 5px 0;
            border: 1px solid #ccc;
            padding: 10px;
            background-color: #eee;
            resize: none;
            font-size: 18px;
            white-space: pre-wrap;
            letter-spacing: 1px;
        }
        .answer .a-item {
            padding: 5px 10px;
            border-radius: 5px;
            margin-bottom: 5px;
        }
        .answer .a-item>label {
            cursor: pointer;
        }
        .checkbox {
            display: none;
        }
        .checkbox-show:before {
            display: inline-block;
            content: '';
            width: 20px;
            height: 20px;
            background-image: url("../img/checkbox.png");
            background-repeat: no-repeat;
            background-size: 100%;
            background-position: 0 -25px;
            vertical-align: bottom;
        }
        .checkbox:checked + .checkbox-show:before {
            background-position: 0 0;
        }

    </style>
</head>
<body>

<div id="app" v-cloak>
    <div v-if=" !start " >
        <button type="button" class="btn btn-primary" @click=" doStart " >点击开始全屏考试</button>
    </div>
    <div v-if=" start " class="menu-left">

        <div class="stu-name" >
            <span>{{loginStu.name}}</span>
            <button type="button" class="btn btn-warning" @click=" submitExamPaper(false) " >交卷</button>
        </div>

        <div style="padding: 10px 5px;">
            <span style="font-size: 16px;color: #ff0000" >违规超过{{exam.count}}次, 将自动交卷</span>
            <button type="button" v-if=" !isFull " class="btn btn-info" @click=" fullObj.doFullScreen() " >全屏</button>
        </div>

        <div class="title" >
            选择题:
        </div>
        <div class="q-list">
            <div :class=" 'q-item' + doGetClassName(q) " v-for="(q,index) in choiceList" @click="doShowQuestion(choiceList[index])" >{{index+1}}</div>
        </div>

        <div class="title" >
            简答题:
        </div>
        <div class="q-list">
            <div :class=" 'q-item' + doGetClassName(q) " v-for="(q,index) in shortAnswerList" @click="doShowQuestion(shortAnswerList[index])" >{{index+1}}</div>
        </div>

        <div class="title" >
            编程题:
        </div>
        <div class="q-list">
            <div :class=" 'q-item' + doGetClassName(q) " v-for="(q,index) in programmingList" @click="doShowQuestion(programmingList[index])" >{{index+1}}</div>
        </div>

    </div>
    <div v-if=" start && isFull " class="menu-right">
        <div class="description">
            <div class="q-title">题目描述:</div>
            <pre class="q-txt" v-text="current.description" ></pre>
        </div>
        <div class="answer" >
            <div class="a-title" >答案:</div>
            <div v-if=" current.typeId == 1 " >
                <!-- 选择题 -->
                <div class="a-item" v-for="(opt,index) in current.optionList" >
                    <label>
                        <input class="checkbox" type="checkbox" :value=" opt.key " v-model="current.stuAnswer">
                        <span class="checkbox-show" ></span>
                        <span>{{opt.key}} : {{opt.value}}</span>
                    </label>
                </div>
            </div>
            <div v-else >
                <!-- :style=" 'height:' + doGetRows(current) + 'px' " -->
                <textarea wrap="hard" :rows="doGetRows(current)" class="a-txt" v-model="current.stuAnswer" ></textarea>
            </div>
        </div>
    </div>

    <div v-if="isShowLoginDialog" class="dialog-box" @click.self=" isShowLoginDialog = false ">
        <div class="dialog-content" >
            <div class="dialog-close" @click=" isShowLoginDialog = false " >
                <svg t="1666015662867" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="876" width="30" height="30">
                    <path d="M872.802928 755.99406 872.864326 755.99406 872.864326 755.624646Z" p-id="877"></path>
                    <path d="M927.846568 511.997953c0-229.315756-186.567139-415.839917-415.838893-415.839917-229.329059 0-415.85322 186.524161-415.85322 415.839917 0 229.300406 186.524161 415.84094 415.85322 415.84094C741.278405 927.838893 927.846568 741.29836 927.846568 511.997953M512.007675 868.171955c-196.375529 0-356.172979-159.827125-356.172979-356.174002 0-196.374506 159.797449-356.157629 356.172979-356.157629 196.34483 0 356.144326 159.783123 356.144326 356.157629C868.152001 708.34483 708.352505 868.171955 512.007675 868.171955" p-id="878"></path>
                    <path d="M682.378947 642.227993 553.797453 513.264806 682.261267 386.229528c11.661597-11.514241 11.749602-30.332842 0.234337-41.995463-11.514241-11.676947-30.362518-11.765975-42.026162-0.222057L511.888971 471.195665 385.223107 344.130711c-11.602246-11.603269-30.393217-11.661597-42.025139-0.059352-11.603269 11.618619-11.603269 30.407544-0.059352 42.011836l126.518508 126.887922L342.137823 639.104863c-11.662621 11.543917-11.780301 30.305213-0.23536 41.96988 5.830799 5.89015 13.429871 8.833179 21.086248 8.833179 7.53972 0 15.136745-2.8847 20.910239-8.569166l127.695311-126.311801L640.293433 684.195827c5.802146 5.8001 13.428847 8.717546 21.056572 8.717546 7.599072 0 15.165398-2.917446 20.968567-8.659217C693.922864 672.681586 693.950494 653.889591 682.378947 642.227993" p-id="879"></path>
                </svg>
            </div>
            <div class="dialog-head" >
                登录
            </div>
            <div class="dialog-body" >
                <form class="center-form80">
                    <div class="form-item">
                        <label class="form-label">用户名:</label>
                        <input class="form-input" type="text" v-model="stu.loginName" >
                    </div>
                    <div class="form-item">
                        <label class="form-label">密码:</label>
                        <input class="form-input" type="password" v-model="stu.pwd" >
                    </div>

                    <div class="form-item text-center">
                        <button type="button" class="btn" @click=" isShowLoginDialog=false; stu.loginName=''; stu.pwd=''; " >关&nbsp;闭</button>
                        <button type="button" class="btn btn-primary" @click=" doStuLogin " >登&nbsp;录</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

<script src="../js/vue.min.js" ></script>
<script src="../js/jquery-3.3.1.min.js" ></script>
<script src="../js/toastr.min.js" ></script>
<script src="../js/base.js" ></script>
<script>
    Vue.config.devtools = true; // 描述浏览器调试工具是否可用
    new Vue({
        el: "#app",
        data: {
            start: false,
            isOver: false, // 是否结束考试了
            loginStu: {
                name: ''
            },
            choiceList: [], // 选择题
            shortAnswerList: [], // 简答题
            programmingList: [], // 编程题
            current: {
                id: 1,
                description: '测试题',
                typeId: 1,
                type: '选择题',
                optionList: [
                    {key:'A', value:'测试1'},
                    {key:'B', value:'测试2'},
                    {key:'C', value:'测试3'},
                    {key:'D', value:'测试4'}
                ],
                score: 2,// 分值
                stuAnswer: [],
                show: false,
                completed: false,// 是否做完
                language: '测试'
            },
            exam: { },
            fullObj: undefined,
            isFull: false,
            count: 0, // 违规次数
            isAutoCommit: false, // 是否开启自动交卷, 考试有违规次数限制, 则开启

            isShowLoginDialog: false, // 是否显示登录框
            stu: { // 用于登录
                loginName: '',
                pwd: ''
            }
        },
        beforeMount() {
            let search = location.search;
            if(search.startsWith("?")) {
                search = search.substr(1);// 获取请求参数
            }
            this.search = search;

            disableSomeCtrl();// 禁用复制, 右键

            let str = localStorage.getItem("stuLogin");
            if(str && str.trim()) {
                try {
                    this.loginStu = JSON.parse(str);
                    // 自动开考
                    // this.doStart();
                    return;
                } catch(e) {
                }
            }
            this.loginStu = null;
            toastr.warning("您未登录！");
            this.isShowLoginDialog = true;
        },
        methods: {
            doStart() {
                if(!this.loginStu) {
                    toastr.warning("您未登录！");
                    this.isShowLoginDialog = true;
                    return;
                }
                if(this.start || this.isOver) {
                    return;
                }

                this.doLoadExamPaper();
            },
            doLoadExamPaper() {
                $.ajax({
                    type: 'post',
                    url: baseUrl + "/front/paper/startExam",
                    data: this.search,
                    dataType: 'json',
                    success: ({msg, success, data, status}) => {
                        if(success) {
                            this.doCheckStuOption();
                            this.start = true;
                            let qtArr = data.questions;
                            if(qtArr.length <= 0) {
                                toastr.error("本试卷未设置考试题目, 请联系管理员");
                            }
                            data.questions = null;
                            this.exam = data;
                            if(this.exam.count > 0) {
                                //this.isAutoCommit = true;
                            }
                            // 如果有保存答案, 则与题目合并
                            let content =  localStorage.getItem("examPaperId-"+this.exam.id);
                            let count =  localStorage.getItem("examPaperCount-"+this.exam.id);
                            // 把数组转换成对象, 方便合并
                            let answerObj = {};
                            if(content && content.trim()) {
                                let stuAns = JSON.parse(content);
                                for(let index in stuAns) {
                                    let answer = stuAns[index];
                                    // 已 questionId 为 key
                                    answerObj[answer.questionId] = answer;
                                }
                            }
                            if(count && count.trim()) {
                                this.count = count*1;
                            }

                            for( let index in qtArr ) {
                                let qt = qtArr[index];
                                qt.show = false;
                                qt.completed = false;// 是否做完. 未用到

                                let an = answerObj[qt.id];
                                qt.stuAnswer = an ? an.answer : '';

                                switch (qt.typeId) {
                                    case 1:// 选择题
                                        //qt.stuAnswer = [];
                                        qt.stuAnswer = an ? an.answer.split(",") : [];

                                        qt.optionList = JSON.parse(qt.optionList);
                                        this.choiceList.push(qt);
                                        break;
                                    case 2:// 简答题
                                        this.shortAnswerList.push(qt);
                                        break;
                                    case 3:// 编程题
                                        this.programmingList.push(qt);
                                        break;
                                }
                            }

                            if(this.choiceList.length > 0) {
                                this.current = this.choiceList[0];
                                this.current.show = true;
                            }
                        } else {
                            toastr.warning(msg);
                            if(status == 401) {// 未登录
                                this.isShowLoginDialog = true;
                            }
                        }
                    },
                    error: (xhr) => {
                        toastr.error('网络异常');
                    }
                });
            },
            doGetClassName(qt) {
                if(qt.show) {
                    return ' q-show';
                }
                if(qt.stuAnswer instanceof Array) {
                    return qt.stuAnswer.length > 0 ? ' q-complete':'';
                }
                return qt.stuAnswer.trim() ? ' q-complete':'';
            },
            doGetRows(qt) {
                let arr = qt.stuAnswer.match(/\n/g);
                let rows = arr ? 3 + arr.length : 2;
                return rows > 26 ? 26: rows;
            },
            doShowQuestion(qt) {
                this.current.show = false;
                qt.show = true;
                this.current = qt;
            },
            submitExamPaper(isAuto) {
                if(!this.start || this.isOver) {
                    return;
                }
                let qtArr = this.getAnswers();
                let content = JSON.stringify(qtArr);
                let param = {
                    examPaperId: this.exam.id,
                    content: content,
                    count: this.count
                };
                // 保存学生的答案, 以便恢复答题
                localStorage.setItem("examPaperId-" + param.examPaperId, content);
                localStorage.setItem("examPaperCount-" + param.examPaperId, this.count+'');


                $.ajax({
                    type: 'post',
                    url: baseUrl + "/front/paper/submit",
                    data: param,
                    dataType: 'json',
                    success: ({msg, success, status}) => {
                        if(success) {
                            // 已交卷, 考试结束
                            this.isOver = true;
                            this.start = false;
                            // 只保留本次的
                            let idArr = [];
                            for(let key in localStorage) {
                                if(key.startsWith("examPaperId-")) {
                                    let id = parseInt( key.replace("examPaperId-", "") );
                                    if(id < param.examPaperId) {
                                        idArr.push(id);
                                    }
                                }
                            }
                            for(let index in idArr) {
                                let id = idArr[index];
                                // 删除之前的
                                localStorage.removeItem("examPaperId-"+id);
                                localStorage.removeItem("examPaperCount-"+id);
                            }

                            toastr.success(msg);
                            return;
                        }
                        toastr.warning(msg);
                        if(status == 401) {// 未登录
                            this.isShowLoginDialog = true;
                        }
                    },
                    error: (xhr) => {
                        toastr.error('网络异常');
                    }
                });
            },
            getAnswers() {
                let qtArr = [];
                // 选择题
                for(let index in this.choiceList) {
                    let qt = this.choiceList[index];
                    qtArr.push({
                        questionId: qt.id,
                        // typeId: qt.typeId,
                        answer: qt.stuAnswer.join(",")
                    });
                }

                // 简答题
                for(let index in this.shortAnswerList) {
                    let qt = this.shortAnswerList[index];
                    qtArr.push({
                        questionId: qt.id,
                        // typeId: qt.typeId,
                        answer: qt.stuAnswer
                    });
                }
                // 编程题
                for(let index in this.programmingList) {
                    let qt = this.programmingList[index];
                    qtArr.push({
                        questionId: qt.id,
                        // typeId: qt.typeId,
                        answer: qt.stuAnswer
                    });
                }
                return qtArr;
            },
            doCheckStuOption() {
                // 检查使用违规
                this.fullObj = window.fullObj;
                this.fullObj.init(() => {
                    if(!this.start || this.isOver) return;

                    if(!this.fullObj.isFullScreen()) {
                        this.count++;

                        // 检查是否进入全屏模式了
                        //this.doViolationCount();
                        if(this.count < this.exam.count){
                            toastr.warning('您退出了全屏模式，已违规！');
                        } else {
                            this.doAutoCommitPaper();
                        }
                    }
                    this.isFull = this.fullObj.isFullScreen();
                });

                // 监测是否离开了当前页面
                document.onvisibilitychange = () => {
                    if(!this.start || this.isOver) {
                        return;
                    }
                    let state = document.visibilityState;
                    //console.log('visibilityState:', state);
                    if(state == 'hidden') {
                        //toastr.warning('您离开了考试页面，已违规！');
                        this.count++;
                        this.doAutoCommitPaper();
                    } else if(state == 'visible') {
                        toastr.success('欢迎回来，但已违规！');
                    }
                };

                this.fullObj.doFullScreen();
            },
            doViolationCount() {
                if(!this.start || this.isOver) return;

                if(this.count < this.exam.count){
                    // 累计违规次数直到全屏
                    toastr.error('10秒内不进入全屏模式，算作违规！');
                    setTimeout(()=>{
                        if(!this.isFull) {
                            this.count++;
                            // 再次检查
                            this.doViolationCount();
                        }
                    }, 10000);
                    return;
                }
                this.doAutoCommitPaper();
            },
            doAutoCommitPaper() {
                if(this.isAutoCommit && this.count >= this.exam.count) {
                    // 超过指定次数, 自动提交
                    toastr.warning('违规次数过多！将自动交卷！');
                    setTimeout(() => {
                        //toastr.success("已自动交卷--测试");
                        this.submitExamPaper(true);
                    }, 500);
                }
            },
            doStuLogin() {
                // 考试时间过长 session 失效, 需重新登录
                $.ajax({
                    type: 'post',
                    url: baseUrl + "/front/stu/login",
                    data: this.stu,
                    dataType: 'json',
                    success: (result) => {
                        toastr[result.success ? "success":"warning"](result.msg);
                        if(result.success) {
                            localStorage.setItem("stuLogin", JSON.stringify(result.data));
                            this.isShowLoginDialog = false;
                            this.stu.pwd = '';
                        }
                    },
                    error: (xhr) => {
                        toastr.error('网络异常');
                    }
                });
            }
        }
    });
</script>
</body>
</html>